/* ==================================================================== *
 *
 * This file is part of Mapics Framework.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author Andrey Cherkashin <action.open@gmail.com>
 *
 * ==================================================================== */

/**
 * Class that construct and controls Map.
 *
 * @package mapics
 * @static
 * @author Andrey Cherkashin <action.open@gmail.com>
 *
 * @param mainDiv (HTMLObject) Where to put map layer
 */
mapics.Map = function(mainDiv)
{
    /**
     * Current map layer in using
     *
     * @var mapics.MapLayer
     */
    this.m_Layer = null;

    /**
     * Container for all divs, controlled by this map
     *
     * May contain map layer div, interface div, overlay divs, etc.
     *
     * @var HTMLObject
     */
    this.m_Container = mainDiv;

    /**
     * List of connected widgets
     */
    this.m_Widgets = [];
};

/**
 * Adds new widget on a map
 *
 * @param widget (IWidget :: mapics.widgets.<Widget>)
 *
 * @return mapics.Map
 */
mapics.Map.prototype.addWidget = function(widget)
{
    // Add widget into list of widgets
    this.m_Widgets.push(widget);

    // Create interface div if its not exists
    if( this.m_UIDiv == null ) {
        this.m_UIDiv = document.createElement('div');
        this.m_UIDiv.setAttribute("style", "position: absolute; z-index: 1000; left: 0px; top: 0px;");
        this.m_Container.appendChild(this.m_UIDiv);
    }

    // Send initialize event
    widget.onAddToMap(this, this.m_UIDiv);
};

/**
 * Removes widget from a map
 *
 * @param widget (IWidget :: mapics.widgets.<Widget>)
 *
 * @return mapics.Map
 */
mapics.Map.prototype.removeWidget = function(widget)
{
    for(var i = 0, max = this.m_Widgets.length; i < max; i++)
    {
        if( this.m_Widgets[i] == widget ) {
            // Send shutdown event
            this.m_Widgets[i].onRemoveFromMap();
            this.m_Widgets.splice(i, 1);
            break;
        }
    }

    return this;
};

/**
 * Returns current map layer
 *
 * @return mapics.MapLayer<Provider>
 */
mapics.Map.prototype.getMapLayer = function() {
    return this.m_Layer;
};

/**
 * Sets current map layer (provider in use)
 * 
 * @example 
 * <code>
 *  // Sets current map layer to Google Maps
 *  map.setMapLayer( new mapics.MapLayerGoogle() );
 *  
 *  // Sets current map layer to Yandex maps
 *  map.setMapLayer( "yandex" ); // or "google"
 * </code>
 *
 * @param mapLayer (mapics.MapLayer|string) MapLayer object or name of provider
 * @param complete (Callback) Callback function
 *
 * @return mapics.Map
 */
mapics.Map.prototype.setMapLayer = function(mapLayer, complete)
{
    var self = this;

    // If mapLayer variable is not object, maybe its a name of provider
    if( typeof(mapLayer) != "object" )
    {
        // Checking var type
        if( typeof(mapLayer) != "string" ) {
            console.error("Can't set map layer: it is not string or MapLayer object");
            return self;
        }

        // Trying to find out name of this MapLayer
        var name = "MapLayer" + mapLayer.charAt(0).toUpperCase() + mapLayer.slice(1);

        // Check if we have this layer exists
        try {
            var mapObject = new window["mapics"][name]();
            mapLayer = mapObject;
        } catch(e) {
            console.error("Can't set map layer: there is no class [mapics." + name + "]");
            return self;
        }
    }

    // If we already have using some layer - we must disable it first
    if( this.m_Layer != null )
    {
        // Save current map state
        this.m_CurrentState = this.m_Layer.getState();

        // Destroy layer
        this.m_Layer.hide();
    }

    // Recreate map layer
    if( this.m_MapDiv != null ) {
        this.m_Container.removeChild(this.m_MapDiv);
    }

    this.m_MapDiv = document.createElement('div');
    this.m_MapDiv.setAttribute("style", "width: 100%; height: 100%; z-index: 1;");
    this.m_Container.appendChild(this.m_MapDiv);

    // Show new map layer
    this.m_Layer = mapLayer;
    this.m_Layer.show(
        this.m_MapDiv,
        function(){
            // If we have saved state, apply it to new map layer
            if( self.m_CurrentState != null ) {
                self.m_Layer.setState( self.m_CurrentState );
                self.m_CurrentState = null;
            }

            // Send callback function
            if( complete ) {
                complete();
            }
        }
    );

    return self;
};